/**
 *     This file is part of cesm-ws.
 *
 *     cesm-ws, Web Service for Community Earth System Model
 *
 *     Copyright (c) 2010, Purdue University and/or affilicates or thrid-party contributors as
 *     indicated by the @author tags or express copyright attribution statements
 *     applied by the authors. All third-party contributions are distributed under
 *     license by Purdue University.
 *
 *     cesm-ws is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with this distribution.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.purdue.rcac.cesm.persistence.model;

import java.sql.Timestamp;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 * Entity class for case in ccsm4
 * 
 * @author Han Zhang
 * 
 */
@Entity
@Table(name = "CESM_CASE_RUNTIME")
@NamedQueries( {
		@NamedQuery(name = CESMCaseRuntime.FIND_BY_ID, query = "SELECT r FROM CESMCaseRuntime r WHERE r.id=:id"),
		@NamedQuery(name = CESMCaseRuntime.FIND_BY_PBSID, query = "SELECT r FROM CESMCaseRuntime r WHERE r.pbsid=:pbsid"),
		@NamedQuery(name = CESMCaseRuntime.FIND_BY_CASE_CONFIG_ID, query = "SELECT r FROM CESMCaseRuntime r WHERE r.caseConfig.id=:cid ORDER BY r.id DESC"),
		@NamedQuery(name = CESMCaseRuntime.FIND_ALL_UNFINISHED, query = "SELECT r FROM CESMCaseRuntime r WHERE r.jobStatus<>'CANCELLED' AND r.jobStatus<>'DONE' AND r.jobStatus<>'COMPLETED_OR_DELETED'") })
public class CESMCaseRuntime {

	public static final String FIND_BY_ID = "find_case_runtime_by_id";
	public static final String FIND_BY_PBSID = "find_case_runtime_by_pbsid";
	public static final String FIND_ALL_UNFINISHED = "find_all_unfinished_case_runtimes";
	public static final String FIND_BY_CASE_CONFIG_ID = "find_case_runtime_by_case_config_id";

	public static Map<Character, JobStatus> JOB_STATUS_MAP;
	static {
		Map<Character, JobStatus> tmp = new HashMap<Character, JobStatus>();
		// standard qstat job-state output char
		tmp.put('B', JobStatus.SUBJOB_RUNNING);
		tmp.put('E', JobStatus.EXITING);
		tmp.put('F', JobStatus.DONE);
		tmp.put('H', JobStatus.HELD);
		tmp.put('Q', JobStatus.QUEUED);
		tmp.put('R', JobStatus.RUNNING);
		tmp.put('S', JobStatus.SUSPENDED);
		tmp.put('T', JobStatus.TRANSPORTED);
		tmp.put('U', JobStatus.SUSPENDED_BY_KEYBOARD);
		tmp.put('W', JobStatus.WAITING);
		tmp.put('X', JobStatus.COMPLETED_OR_DELETED);
		
		// added job-state output char
		tmp.put('C', JobStatus.CANCELLED);
		JOB_STATUS_MAP = Collections.unmodifiableMap(tmp);
	}

	public enum JobStatus {
		SUBMITTED, SUBJOB_RUNNING, EXITING, HELD, QUEUED, RUNNING, SUSPENDED, TRANSPORTED, SUSPENDED_BY_KEYBOARD, WAITING, COMPLETED_OR_DELETED, DONE, CANCELLED
	}

	/**
	 * Fields
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
	@JoinColumn(name = "cid", nullable = false)
	private CESMCaseConfig caseConfig;

	@Enumerated(EnumType.STRING)
	private JobStatus jobStatus;

	private String pbsid;

	@Column(name = "stime", nullable = false)
	private Timestamp startTime;

	@Column(name = "u_walltime")
	private String usedWallTime;

	@Column(name = "u_cputime")
	private String usedCPUTime;

	@Column(name = "queue")
	private String queue;

	/**
	 * Constructors
	 */
	public CESMCaseRuntime() {
		this("");
	}

	public CESMCaseRuntime(String pbsid) {
		super();
		this.pbsid = pbsid;
		this.jobStatus = JobStatus.SUBMITTED;
		this.startTime = new Timestamp(new Date().getTime());
		this.usedCPUTime = "--";
		this.usedWallTime = "--";
		this.queue = "";
	}

	public CESMCaseRuntime(String pbsid, CESMCaseConfig caseConfig) {
		this(pbsid);
		this.caseConfig = caseConfig;
	}

	/**
	 * Getters & Setters
	 */
	public void setCaseConfig(CESMCaseConfig caseConfig) {
		this.caseConfig = caseConfig;
	}

	public Long getId() {
		return id;
	}

	public String getPbsid() {
		return pbsid;
	}

	public void setPbsid(String pbsid) {
		this.pbsid = pbsid;
	}

	public JobStatus getJobStatus() {
		return jobStatus;
	}

	public void setJobStatus(JobStatus jobStatus) {
		this.jobStatus = jobStatus;
	}

	public Timestamp getStartTime() {
		return startTime;
	}

	public String getUsedWallTime() {
		return usedWallTime;
	}

	public void setUsedWallTime(String usedWallTime) {
		this.usedWallTime = usedWallTime;
	}

	public String getUsedCPUTime() {
		return usedCPUTime;
	}

	public void setUsedCPUTime(String usedCPUTime) {
		this.usedCPUTime = usedCPUTime;
	}

	public CESMCaseConfig getCaseConfig() {
		return caseConfig;
	}

	public String getQueue() {
		return queue;
	}

	public void setQueue(String queue) {
		this.queue = queue;
	}

	/**
	 * Override toString
	 */
	public String toString() {
		return String.format("<CESMCaseRuntime>\n\t" + "id=%d\n\t"
				+ "cid=%d\n\t" + "startTime=%s\n\t" + "pbsid=%s\n\t"
				+ "queue=%s\n\t" + "status=%s", id, caseConfig.getId(),
				startTime.toString(), pbsid, queue, jobStatus);
	}

	public boolean isDone() {
		return this.jobStatus == JobStatus.DONE
				|| this.jobStatus == JobStatus.COMPLETED_OR_DELETED;
	}
}
